/*
    @file: log/source/LogDispatcher.cpp
    @author: Wolfhead
 */
#include "LogDispatcher.h"
#include <boost/foreach.hpp>


namespace logger
{

LogDispatcher::LogDispatcher()
{

}

LogDispatcher::~LogDispatcher()
{
    clear();
}

int LogDispatcher::add(const std::string& name, const LogOption& option)
{
    // not allow an empty runner
    if (!option.logger_ptr)
    {
        return -1;
    }

    boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

    if (m_name_map.find(name) == m_name_map.end())
    {
        LogRunnerPtr runner_ptr(new LogRunner(option));

        m_runner.push_back(runner_ptr);
        m_name_map[name] = runner_ptr;

        compute_priority();

        if (option.start_on_create)
        {
            runner_ptr->start();
        }
    }
    else
    {
        return -1;
    }
    
    return 0;
}

int LogDispatcher::start(const std::string& name)
{
    boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

    std::map<std::string, LogRunnerPtr>::iterator it =
        m_name_map.find(name);

    if (it == m_name_map.end())
    {
        return -1;
    }

    it->second->start();


    return 0;   
}

int LogDispatcher::start()
{
    boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

    LogRunnerPtr runner_ptr;
    BOOST_FOREACH(runner_ptr, m_runner)
    {
        runner_ptr->start();
    }

    return 0;       
}

int LogDispatcher::remove(const std::string& name)
{
    boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

    if (m_name_map.find(name) == m_name_map.end())
    {
        return -1;
    }
    else
    {
        LogRunnerPtr runner_ptr = m_name_map[name];

        m_name_map.erase(name);

        for (std::vector<LogRunnerPtr>::iterator it = m_runner.begin();
             it != m_runner.end();
             ++it)
        {
             if (*it == runner_ptr)
             {
                it = m_runner.erase(it);
                if (it == m_runner.end())
                {
                    break;  
                }
             }
        }

        runner_ptr->stop();

        compute_priority();
    }

    return 0;
}

int LogDispatcher::clear()
{
    boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

    m_name_map.clear();

    LogRunnerPtr runner_ptr;
    BOOST_FOREACH(runner_ptr, m_runner)
    {
        runner_ptr->stop();
    }

    m_runner.clear();   

    return 0;
}

int LogDispatcher::set_option(
    const std::string& name,
    const LogOption& option)
{
    boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

    std::map<std::string, LogRunnerPtr>::iterator it =
        m_name_map.find(name);

    if (it == m_name_map.end())
    {
        return -1;
    }

    it->second->set_option(option);

    compute_priority();

    return 0;
}

int LogDispatcher::get_option(
    const std::string& name,
    LogOption& option
    )
{
    boost::shared_lock<boost::shared_mutex> shared_lock(m_mutex);

    std::map<std::string, LogRunnerPtr>::iterator it =
        m_name_map.find(name);

    if (it == m_name_map.end())
    {
        return -1;
    }   

    option = it->second->get_option();

    return 0;
}


int LogDispatcher::log(LogDataPtr data_ptr)
{
    boost::shared_lock<boost::shared_mutex> shared_lock(m_mutex);

    // use priority dispatch
    if (!data_ptr->by_name)
    {
        LogRunnerPtr runner_ptr;
        BOOST_FOREACH(runner_ptr, m_runner)
        {
            runner_ptr->log(data_ptr);
        }
    }
    else
    {
        std::map<std::string, LogRunnerPtr>::iterator it =
            m_name_map.find(data_ptr->name);
        if (it == m_name_map.end())
        {
            return -1;
        }

        it->second->log(data_ptr);      
    }
    return 0;
}

int LogDispatcher::compute_priority()
{
    LogPriority priority = kNone;
    for (size_t i = 0; i != m_runner.size(); ++i)
    {
        priority |= m_runner[i]->get_option().priority;
    }

    m_aggregate_priority = priority;
    return 0;
}

}//namespace logger
